package cn.com.weixin.sdk.serviceImpl;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import cn.com.weixin.sdk.api.ApiConfigKit;
import cn.com.weixin.sdk.api.ApiResult;
import cn.com.weixin.sdk.api.MediaApi;
import cn.com.weixin.sdk.api.MediaArticles;
import cn.com.weixin.sdk.api.MessageApi;
import cn.com.weixin.sdk.kit.HttpKit;
import cn.com.weixin.sdk.kit.MsgEncryptKit;
import cn.com.weixin.sdk.kit.SignatureCheckKit;
import cn.com.weixin.sdk.kit.StrKit;
import cn.com.weixin.sdk.msg.InMsgParser;
import cn.com.weixin.sdk.msg.in.InImageMsg;
import cn.com.weixin.sdk.msg.in.InLinkMsg;
import cn.com.weixin.sdk.msg.in.InLocationMsg;
import cn.com.weixin.sdk.msg.in.InMsg;
import cn.com.weixin.sdk.msg.in.InShortVideoMsg;
import cn.com.weixin.sdk.msg.in.InTextMsg;
import cn.com.weixin.sdk.msg.in.InVideoMsg;
import cn.com.weixin.sdk.msg.in.InVoiceMsg;
import cn.com.weixin.sdk.msg.in.event.InCustomEvent;
import cn.com.weixin.sdk.msg.in.event.InFollowEvent;
import cn.com.weixin.sdk.msg.in.event.InLocationEvent;
import cn.com.weixin.sdk.msg.in.event.InMassEvent;
import cn.com.weixin.sdk.msg.in.event.InMenuEvent;
import cn.com.weixin.sdk.msg.in.event.InPoiCheckNotifyEvent;
import cn.com.weixin.sdk.msg.in.event.InQrCodeEvent;
import cn.com.weixin.sdk.msg.in.event.InShakearoundUserShakeEvent;
import cn.com.weixin.sdk.msg.in.event.InTemplateMsgEvent;
import cn.com.weixin.sdk.msg.in.event.InVerifyFailEvent;
import cn.com.weixin.sdk.msg.in.event.InVerifySuccessEvent;
import cn.com.weixin.sdk.msg.in.event.InWifiEvent;
import cn.com.weixin.sdk.msg.in.speech_recognition.InSpeechRecognitionResults;
import cn.com.weixin.sdk.msg.out.OutMsg;
import cn.com.weixin.sdk.service.WeiXxinService;
import cn.com.weixin.sdk.service.WxMsgService;

public abstract class WXAbstractServiceImpl implements WeiXxinService,
		WxMsgService {
	static Logger logger = Logger.getLogger(WeiXxinService.class);

	public String getInMsgXml(HttpServletRequest request) {
		logger.info("getInMsgXml0");
		String inMsgXml = null;
		inMsgXml = HttpKit.readData(request);
		logger.info("getInMsgXml1");
		// 是否需要解密消息
		if (ApiConfigKit.getApiConfig().isEncryptMessage()) {
			inMsgXml = MsgEncryptKit.decrypt(inMsgXml,
					request.getParameter("timestamp"),
					request.getParameter("nonce"),
					request.getParameter("msg_signature"));
		}
		return inMsgXml;
	}

	public InMsg getInMsg(String inMsgXml) {
		InMsg inMsg = InMsgParser.parse(inMsgXml);
		return inMsg;
	}

	public void dispacth(HttpServletRequest request,
			HttpServletResponse response) {
		// 开发模式输出微信服务发送过来的 xml 消息
		String InMsgXml=getInMsgXml(request);
		if (ApiConfigKit.isDevMode()) {
			System.out.println("re message:");
			System.out.println(InMsgXml);
		}
		// 解析消息并根据消息类型分发到相应的处理方法
		InMsg msg = getInMsg(InMsgXml);
		OutMsg outMsg = null;
		if (msg instanceof InTextMsg)
			if(((InTextMsg) msg).getContent().equals("群发")){
				String  path =request.getSession().getServletContext().getRealPath("/upload/");
				path+="image/index_6.jpg";
				ApiResult result=MediaApi.addMaterial(new File(path), "ddd", "dddd");
				System.out.println("upload image=\n"+result);
				String thumb_media_id=result.getStr("media_id");//media_id
				List<MediaArticles> mediaArticles=new ArrayList<MediaArticles>();
				for(int i=0;i<4;i++){
					MediaArticles m=new MediaArticles();
					m.setAuthor("");
					m.setContent("<p>p标签</p>kdjskajfksdjfkjaskdljfklsdjfkjskadjf");
					m.setContent_source_url("http://www.gdzhxny.com/web/news/29.html");
					m.setShow_cover_pic(false);
					m.setThumb_media_id(thumb_media_id);
					m.setTitle("群发数字");
					mediaArticles.add(m);
				}
				ApiResult result1=MediaApi.addNews(mediaArticles);
				System.out.println("upload news=\n"+result1);
				String media_id=result1.getStr("media_id");
				StringBuilder json=new StringBuilder();
				json.append("{");
				json.append("\"filter\":{");
				json.append("\"is_to_all\":fase,");
				json.append("\"group_id\":\"2\"");
				json.append("},");
				json.append("\"mpnews\":{");
				json.append("\"media_id\":\""+media_id+"\"");
				json.append("},");
				json.append("\"msgtype\":\"mpnews\"");
				json.append("}");
				ApiResult result2=MessageApi.sendAll(json.toString());
				System.out.println("send all=\n"+result2);
				outMsg = processInTextMsg((InTextMsg) msg);
			}else{

				outMsg = processInTextMsg((InTextMsg) msg);
			}

		else if (msg instanceof InImageMsg)
			outMsg = processInImageMsg((InImageMsg) msg);
		// update by unas at
		// 2016-1-29,
		// 由于继承InVoiceMsg，需要在InVoiceMsg前判断类型
		else if (msg instanceof InSpeechRecognitionResults)
			outMsg = processInSpeechRecognitionResults((InSpeechRecognitionResults) msg);
		else if (msg instanceof InVoiceMsg)
			outMsg = processInVoiceMsg((InVoiceMsg) msg);
		else if (msg instanceof InVideoMsg)
			outMsg = processInVideoMsg((InVideoMsg) msg);
		else if (msg instanceof InShortVideoMsg) // 支持小视频
			outMsg = processInShortVideoMsg((InShortVideoMsg) msg);
		else if (msg instanceof InLocationMsg)
			outMsg = processInLocationMsg((InLocationMsg) msg);
		else if (msg instanceof InLinkMsg)
			outMsg = processInLinkMsg((InLinkMsg) msg);
		else if (msg instanceof InCustomEvent)
			outMsg = processInCustomEvent((InCustomEvent) msg);
		else if (msg instanceof InFollowEvent)
			outMsg = processInFollowEvent((InFollowEvent) msg);
		else if (msg instanceof InQrCodeEvent)
			outMsg = processInQrCodeEvent((InQrCodeEvent) msg);
		else if (msg instanceof InLocationEvent)
			outMsg = processInLocationEvent((InLocationEvent) msg);
		else if (msg instanceof InMassEvent)
			outMsg = processInMassEvent((InMassEvent) msg);
		else if (msg instanceof InMenuEvent)
			outMsg = processInMenuEvent((InMenuEvent) msg);
		else if (msg instanceof InTemplateMsgEvent)
			outMsg = processInTemplateMsgEvent((InTemplateMsgEvent) msg);
		else if (msg instanceof InShakearoundUserShakeEvent)
			outMsg = processInShakearoundUserShakeEvent((InShakearoundUserShakeEvent) msg);
		else if (msg instanceof InVerifySuccessEvent)
			outMsg = processInVerifySuccessEvent((InVerifySuccessEvent) msg);
		else if (msg instanceof InVerifyFailEvent)
			outMsg = processInVerifyFailEvent((InVerifyFailEvent) msg);
		else if (msg instanceof InPoiCheckNotifyEvent)
			outMsg = processInPoiCheckNotifyEvent((InPoiCheckNotifyEvent) msg);
		else if (msg instanceof InWifiEvent)
			outMsg = processInWifiEvent((InWifiEvent) msg);
		else
			logger.error("未能识别的消息类型。 消息 xml 内容为：\n" + InMsgXml);

		this.render(outMsg, "text/xml", request, response);
	}

	public void handlerMsg(HttpServletRequest request,
			HttpServletResponse response) {
		logger.info("handlerMsg");
		try {
			// 将 ApiConfig 对象与当前线程绑定，以便在后续操作中方便获取该对象：
			// ApiConfigKit.getApiConfig();
			// ApiConfigKit.setThreadLocalApiConfig(getApiConfig());

			// 如果是服务器配置请求，则配置服务器并返回
			if (isConfigServerRequest(request)) {
				logger.info("isConfigServerRequest");
				configServer(request, response);
				return;
			}

			logger.info("handlerMsg1");
			// 对开发测试更加友好
			if (ApiConfigKit.isDevMode()) {
				logger.info("isDevMode");
				dispacth(request, response);
			} else {
				logger.info("handlerMsg2");
				// 签名检测
				if (checkSignature(request, response)) {
					logger.info("checkSignature");
					dispacth(request, response);
					logger.info("dispacth");
				} else {
					logger.info("handlerMsg2 error");
					logger.info("签名验证失败，请确定是微信服务器在发送消息过来");
					render("签名验证失败，请确定是微信服务器在发送消息过来", response);

				}
			}

		} finally {
			logger.info("handlerMsg1 over");
			// ApiConfigKit.removeThreadLocalApiConfig();
		}
	}

	/**
	 * 是否为开发者中心保存服务器配置的请求
	 */
	private boolean isConfigServerRequest(HttpServletRequest request) {
		return StrKit.notBlank(request.getParameter("echostr"));
	}

	/**
	 * 配置开发者中心微信服务器所需的 url 与 token
	 * 
	 * @return true 为config server 请求，false 正式消息交互请求
	 */
	public void configServer(HttpServletRequest request,
			HttpServletResponse response) {
		logger.info("configServer");
		// 通过 echostr 判断请求是否为配置微信服务器回调所需的 url 与 token
		String echostr = request.getParameter("echostr");
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		boolean isOk = SignatureCheckKit.me.checkSignature(signature,
				timestamp, nonce);
		if (isOk)
			render(echostr, response);
		else
			logger.error("验证失败：configServer");
	}

	@Override
	public boolean checkSignature(HttpServletRequest request,
			HttpServletResponse response) {
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		if (StrKit.isBlank(signature) || StrKit.isBlank(timestamp)
				|| StrKit.isBlank(nonce)) {
			render("check signature failure", response);
			return false;
		}

		if (SignatureCheckKit.me.checkSignature(signature, timestamp, nonce)) {
			return true;
		} else {
			logger.error("check signature failure: " + " signature = "
					+ request.getParameter("signature") + " timestamp = "
					+ request.getParameter("timestamp") + " nonce = "
					+ request.getParameter("nonce"));

			return false;
		}
	}

	@Override
	public void render(OutMsg outMsg, String contentType,
			HttpServletRequest request, HttpServletResponse response) {
		String outMsgXml = outMsg.toXml();
		// 开发模式向控制台输出即将发送的 OutMsg 消息的 xml 内容
		if (ApiConfigKit.isDevMode()) {
			System.out.println("发送消息:");
			System.out.println(outMsgXml);
			System.out
					.println("--------------------------------------------------------------------------------\n");
		}

		// 是否需要加密消息
		if (ApiConfigKit.getApiConfig().isEncryptMessage()) {
			outMsgXml = MsgEncryptKit.encrypt(outMsgXml,
					request.getParameter("timestamp"),
					request.getParameter("nonce"));
		}
		PrintWriter writer = null;
		try {
			// HTTP/1.0 caches might
			// not implement
			// Cache-Control and
			// might only implement
			// Pragma: no-cache
			response.setHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);
			response.setContentType(contentType);
			response.setCharacterEncoding("UTF-8"); // 默认编码

			writer = response.getWriter();
			writer.write(outMsgXml);
			writer.flush();
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			if (writer != null)
				writer.close();
		}
	}

	@Override
	public void render(String text, HttpServletResponse response) {
		PrintWriter writer = null;
		try {
			// HTTP/1.0 caches might
			// not implement
			// Cache-Control and
			// might only implement
			// Pragma: no-cache
			response.setHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);
			response.setContentType("text/plain");
			response.setCharacterEncoding("UTF-8"); // 默认编码

			writer = response.getWriter();
			writer.write(text);
			writer.flush();
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			if (writer != null)
				writer.close();
		}
	}

	@Override
	public abstract OutMsg processInTextMsg(InTextMsg inTextMsg);

	@Override
	public abstract OutMsg processInImageMsg(InImageMsg inImageMsg);

	@Override
	public abstract OutMsg processInVoiceMsg(InVoiceMsg inVoiceMsg);

	@Override
	public abstract OutMsg processInVideoMsg(InVideoMsg inVideoMsg);

	@Override
	public abstract OutMsg processInShortVideoMsg(
			InShortVideoMsg inShortVideoMsg);

	@Override
	public abstract OutMsg processInLocationMsg(InLocationMsg inLocationMsg);

	@Override
	public abstract OutMsg processInLinkMsg(InLinkMsg inLinkMsg);

	@Override
	public abstract OutMsg processInCustomEvent(InCustomEvent inCustomEvent);

	@Override
	public abstract OutMsg processInFollowEvent(InFollowEvent inFollowEvent);

	@Override
	public abstract OutMsg processInQrCodeEvent(InQrCodeEvent inQrCodeEvent);

	@Override
	public abstract OutMsg processInLocationEvent(
			InLocationEvent inLocationEvent);

	@Override
	public abstract OutMsg processInMassEvent(InMassEvent inMassEvent);

	@Override
	public abstract OutMsg processInMenuEvent(InMenuEvent inMenuEvent);

	@Override
	public abstract OutMsg processInSpeechRecognitionResults(
			InSpeechRecognitionResults inSpeechRecognitionResults);

	@Override
	public abstract OutMsg processInTemplateMsgEvent(
			InTemplateMsgEvent inTemplateMsgEvent);

	@Override
	public abstract OutMsg processInShakearoundUserShakeEvent(
			InShakearoundUserShakeEvent inShakearoundUserShakeEvent);

	@Override
	public abstract OutMsg processInVerifySuccessEvent(
			InVerifySuccessEvent inVerifySuccessEvent);

	@Override
	public abstract OutMsg processInVerifyFailEvent(
			InVerifyFailEvent inVerifyFailEvent);

	@Override
	public abstract OutMsg processInPoiCheckNotifyEvent(
			InPoiCheckNotifyEvent inPoiCheckNotifyEvent);

	@Override
	public abstract OutMsg processInWifiEvent(InWifiEvent inWifiEvent);

	@Override
	public void handlerApi(HttpServletRequest request,
			HttpServletResponse response) {
		// TODO Auto-generated method stub

	}

	@Override
	public void handlerMenu(HttpServletRequest request,
			HttpServletResponse response) {
		// TODO Auto-generated method stub

	}

}
